package sjp.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Solution {
    private final static char types[] = new char[]{'A', 'B', 'C', 'D'};


    private static List<String> getAll(int num) {
        if (num == 0) {
            return Collections.emptyList();
        }
        if (num == 1) {
            return Arrays.asList("A", "B", "C", "D");
        }
        List<String> subs = getAll(num - 1);
        //printList(subs);

        List<String> list = new ArrayList<>();
        for (int i = 0; i < types.length; i++) {
            for (String s : subs) {
                list.add(types[i] + s);
            }
        }
        return list;
    }

    private static void printList(List<String> list) {
        for (String s : list) {
            System.out.println(s);
        }
    }

    public static void main(String[] args) {
        List<String> strings = getAll(10);
        //printList(strings);
        System.out.println(strings.size());
        int i = 0;
        for (String string : strings) {
            if (test(string)) {
                i++;
                System.out.println(string);
            }
        }
        System.out.println(i);
    }

    public static boolean test(String str) {
        char[] a = str.toCharArray();
        //2
        if (!testQ2(a)) {
            return false;
        }
        //3
        if (!testQ3(a)) {
            return false;
        }
        if (!testQ4(a)) {
            return false;
        }
        if (!testQ5(a)) {
            return false;
        }
        if (!testQ6(a)) {
            return false;
        }
        if (!testQ9(a)) {
            return false;
        }
        if (!testQ10(a)) {
            return false;
        }
        return true;
    }

    private static boolean testQ2(char[] a) {
        if (a[1] == 'A') {
            if (a[4] != 'C') {
                return false;
            }
        } else if (a[1] == 'B') {
            if (a[4] != 'D') {
                return false;
            }

        } else if (a[1] == 'C') {
            if (a[4] != 'A') {
                return false;
            }

        } else if (a[1] == 'D') {
            if (a[4] != 'B') {
                return false;
            }
        }
        return true;
    }

    private static boolean testQ3(char[] a) {
        if (a[2] == 'A') {
            return equals(a, 2, 4, 6) && not(a, 2, 4, 6, 'A');
        }
        if (a[2] == 'B') {
            return equals(a, 2, 3, 4) && not(a, 2, 3, 4, 'B');
        }
        if (a[2] == 'C') {
            return equals(a, 3, 4, 6) && not(a, 3, 4, 6, 'C');
        }
        if (a[2] == 'D') {
            return equals(a, 2, 3, 6) && not(a, 2, 3, 6, 'D');
        }
        return false;
    }

    private static boolean testQ4(char[] a) {
        if (a[3] == 'A') {
            return equals(a, 1, 5);
        }
        if (a[3] == 'B') {
            return equals(a, 2, 7);
        }
        if (a[3] == 'C') {
            return equals(a, 1, 9);
        }
        if (a[3] == 'D') {
            return equals(a, 6, 10);
        }
        return false;
    }

    private static boolean testQ5(char[] a) {
        if (a[4] == 'A') {
            return a[4] == a[7];
        }
        if (a[4] == 'B') {
            return a[4] == a[3];
        }
        if (a[4] == 'C') {
            return a[4] == a[8];
        }
        if (a[4] == 'D') {
            return a[4] == a[6];
        }
        return false;
    }

    private static boolean testQ6(char[] a) {
        if (equals(a, 2, 4, 8)) {

        } else if (equals(a, 1, 6, 8)) {

        } else if (equals(a, 3, 10, 8)) {

        } else if (equals(a, 5, 9, 8)) {

        } else {
            return false;
        }
        return true;
    }

    private static boolean testQ9(char[] a) {
        boolean flag1 = a[0] == a[5];
        if (a[8] == 'A') {
            return flag1 != (a[4] == a[5]);
        }
        if (a[8] == 'B') {
            return flag1 != (a[4] == a[9]);
        }
        if (a[8] == 'C') {
            return flag1 != (a[4] == a[1]);
        }
        if (a[8] == 'D') {
            return flag1 != (a[4] == a[8]);
        }
        return false;
    }

    private static boolean testQ10(char[] a) {
        int[] counts = getCount(a);
        int v = getMaxCount(counts) - getMinCount(counts);
        //System.out.println(v);
        if (a[9] == 'A') {
            return v == 3;
        }
        if (a[9] == 'B') {
            return v == 2;
        }
        if (a[9] == 'C') {
            return v == 4;
        }
        if (a[9] == 'D') {
            return v == 1;
        }
        return false;
    }

    private static boolean not(char[] arr, int a, int b, int c, char val) {
        return arr[a - 1] != val && arr[b - 1] != val && arr[c - 1] != val;
    }

    private static boolean equals(char[] arr, int a, int b, int c) {
        return arr[a - 1] == arr[b - 1] && arr[b - 1] == arr[c - 1];
    }

    private static boolean equals(char[] arr, int a, int b) {
        return arr[a - 1] == arr[b - 1];
    }

    private static int[] getCount(char[] arr) {
        int countA = 0;
        int countB = 0;
        int countC = 0;
        int countD = 0;

        for (char c : arr) {
            if (c == 'A') {
                countA++;
            } else if (c == 'B') {
                countB++;
            } else if (c == 'C') {
                countC++;
            } else if (c == 'D') {
                countD++;
            }
        }
        return new int[]{countA, countB, countC, countD};
    }

    private static int getMinCount(int[] numArr) {
        int min = numArr[0];
        for (int i : numArr) {
            if (i < min) {
                min = i;
            }
        }
        return min;
    }

    private static int getMaxCount(int[] numArr) {
        int max = numArr[0];
        for (int i : numArr) {
            if (i > max) {
                max = i;
            }
        }
        return max;
    }

}
